#pragma once

#include<queue>
#include<mutex>
#include<pthread.h>
#include"LockGuard.hpp"

#define DEF_SIZE 10

namespace wbj
{

    template<class T>
    class BlockQueue
    {
    public:
        BlockQueue(size_t cap=DEF_SIZE)  
        :_cap(cap)  
        {
            pthread_mutex_init(&_mtx,nullptr);
            pthread_cond_init(&_pro_cond,nullptr);
            pthread_cond_init(&_con_cond,nullptr);
        }

        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_pro_cond);
            pthread_cond_destroy(&_con_cond);
        }

        void Push(const T& inDate)
        {
            LockGuard lock(&_mtx);
            while(IsFull())
            {
                pthread_cond_wait(&_pro_cond,&_mtx);
            }
            _queue.push(inDate);

            pthread_cond_signal(&_con_cond);

        }

        void Pop(T* outDate)
        {
            LockGuard lock(&_mtx);
            while(IsEmpty())
            {
                pthread_cond_wait(&_con_cond,&_mtx);
            }
            *outDate=_queue.front();
            _queue.pop();

            pthread_cond_signal(&_pro_cond);
        }

        bool IsEmpty()
        {
            return _queue.empty();
        }

        bool IsFull()
        {
            return _queue.size()==_cap;
        }
    private:
        std::queue<T> _queue;
        size_t _cap;
        pthread_mutex_t _mtx;
        pthread_cond_t _pro_cond;
        pthread_cond_t _con_cond;
    };
}